前兩篇介紹完 Vuex 的核心概念,最後當中大型專案需要組織較為複雜的資料結構時,總不可能一個 index.js 就塞滿所有資料量,這會造成取用和管理上的不便,因此勢必得經過一番模組化,將過於龐大的資料分門別類,同時搭配使用 Map Helpers 來簡化冗長程式碼。
將 Store 分割成多組 module,每個 module 內部各自擁有其自己的 state、getter、mutation、action。
// member.js
export default ({
  namespaced: true,
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
})
// store/index.js
import member from './member.js'
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
  modules: {
    member,
		...
  }
})
在 module 內部設定 namespaced: true,使其成為帶有指定名稱的 module,當 module 被註冊之後,其內部擁有的所有註冊路徑也會跟著調整命名,取用時也能迅速得知模組來源。
store.state.member.name
store.getters["member/name"]
訪問全域資料:
模組化的 getters 函式,可取用的參數依序為 state、getters、rootState、rootGetters。
store.state 和 store.getters,差別在於 Vuex.Store 實例屬性為唯讀狀態// root.js
state: {
	number: 20
}
// member.js => module name: member
state: {
	name: 'John'
}
getters: {
	name: state => state.name,
}
// test.js => module name: test
getters: {
	rootNumber: (state, getters, rootState) => rootState.number,
	memberName: (state, getters, rootState, rootGetters) => 
        rootGetters['member/name']
}
console.log(this.$store.getters["test/rootNumber"]) // 20 
console.log(this.$store.getters["test/memberName"]) // John
dispatch 和 commit 的第三個可選參數(options?: Object)若設定為 { root: true },則可跨域取用命名模組的 root actions 或 root mutations。
// member.js => module name: member
actions: {
    getName: {...},
}
// test.js
actions: {
    getAllData(context): {
        context.dispatch("member/getName", null, { root: true });
	},
}
註冊為全域 action:在 action 內設定 { root: true },並將 action 函式定義為 handler,便能在全域中使用 dispatch 呼叫該 action。
// member.js => module name: member
actions: {
    getMemberName: {
      root: true,
      handler(context, payload) {...},
    },
}
store.dispatch("member/getMemberName"); // 非全域 action
store.dispatch("getMemberName"); // 設定 root: true 註冊為全域 action
初學時總會先使用最基本的語法來取用 Vuex 資料:
computed:{
	name(){
		return this.$store.getters["member/name"];
	}
}
然而一旦取用的資料愈來愈多,並且資料皆來自不同的模組時,取用過程便會變成一長串重複又冗長的內容,因此 Map Helpers 正是解決困擾的重要幫手,四個核心概念各有所屬的 Helper 物件——mapState、mapGetters、mapMutations、mapActions,透過物件展開運算符(Object Rest/Spread Properties for ECMAScript)簡化程式碼。
首先需將 Helper 引入:
import { mapGetters } from 'vuex'
mapGetters陣列寫法:應用於單層結構
computed: {
  ...mapGetters(['name','age','address','birth', ...])
}
物件寫法:應用於模組化 Store
可以為 getter 重新命名:
computed: {
  ...mapGetters({
    memberAge: 'member/age',
    memberName: 'member/name',
  })
}
// this.$store.getters["member/name"] 變成 this.memberName
相同模組的 getter 可以提取出模組名稱:
computed: {
  ...mapGetters('member',{
    memberAge: 'age',
    memberName: 'name',
  })
}
物件結合陣列寫法:已提取模組名稱,但無命名需求,則可結合陣列形式更為精簡
computed: {
  ...mapGetters('member',['age','name'])
}
mapMutations、mapActions在 methods 中使用 mapMutations 及 mapActions,兩者也都可以帶入 payload 參數。
import { mapMutations, mapActions } from 'vuex';
methods: {
  ...mapMutations({
		books: 'bookList',
		// this.$store.commit('bookList') 變成 this.books()
	})
  ...mapActions(['fetchBookList', 'fetchBook']), 
		// this.$store.dispatch('fetchBookList') 變成 this.fetchBookList()
		// this.$store.dispatch('fetchBook', ISBNId) 變成 this.fetchBook(ISBNId)
}
因為若一律透過 getter 取用 state,基本上就比較少有透過 mapState 取用 state 的機會,因此本篇就先略過介紹了,有興趣的話也可以讀 Vuex 文件「The mapState Helper」了解,用法上應該大同小異。